package online

import (
	"errors"
	"server/common"

	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
)

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *OnlineService) checkCallEndReqData(data common.CallEndReqData) error {
	// Check if call ID is provided
	if data.CallId == "" {
		return errors.New("call ID is required in call end request")
	}

	// Check if user ID is provided
	if data.UserId == "" {
		return errors.New("user ID is required in call end request")
	}

	// Check if call exists
	if !s.callMgr.CallExists(data.CallId) {
		return errors.New("call does not exist: " + data.CallId)
	}

	// Check if user is part of the call
	if !s.callMgr.UserInCall(data.CallId, data.UserId) {
		return errors.New("user is not part of the call: " + data.UserId)
	}

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *OnlineService) sendCallEndResponse(rid string, code int, msg string,
	reqData common.CallEndReqData, connId string) {
	responseMsg := common.Message{
		Cmd: common.CALL_END_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: code,
			Msg:  msg,
			Data: common.CallEndResData{
				CallId: reqData.CallId,
				UserId: reqData.UserId,
			},
		},
	}

	s.dispatcher.Dispatch(responseMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *OnlineService) sendCallEndNotify(rid string, reqData common.CallEndReqData) {
	peerUserId, err := s.callMgr.GetPeerUserId(reqData.CallId, reqData.UserId)
	if err != nil {
		LOG(rid).WithError(err).Error("failed to get peer user ID")
		return
	}

	peerUser := s.userMgr.GetUserByUserId(peerUserId)
	if peerUser == nil {
		LOG(rid).Error("peer user not found: " + peerUserId)
		return
	}

	responseMsg := common.Message{
		Cmd: common.CALL_END_NOTIFY,
		Rid: rid,
		Data: common.CallEndNotifyData{
			CallId: reqData.CallId,
			UserId: peerUserId,
		},
	}

	s.dispatcher.Dispatch(responseMsg, s.serviceInfo, common.AccessServiceInfo, peerUser.ConnId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *OnlineService) handleCallEndReq(msg common.Message, from common.ServiceInfo,
	connId string) error {
	common.Logger(common.SERVICE_TYPE_ONLINE, msg.Rid).WithFields(logrus.Fields{
		"msg":    common.ToJson(msg),
		"from":   from,
		"connId": connId,
	}).Info("call handleCallEndReq")

	var reqData common.CallEndReqData
	if err := mapstructure.Decode(msg.Data, &reqData); err != nil {
		LOG(msg.Rid).WithError(err).Error("failed to decode call end request data")
		s.sendCallEndResponse(msg.Rid, 1, err.Error(), reqData, connId)
		return nil
	}

	if err := s.checkCallEndReqData(reqData); err != nil {
		s.sendCallEndResponse(msg.Rid, 1, err.Error(), reqData, connId)
		return nil
	}

	// Send the call end response
	s.sendCallEndResponse(msg.Rid, 0, "Call end request processed successfully", reqData, connId)

	// Notify the peer user about the call end
	s.sendCallEndNotify(msg.Rid, reqData)

	// Remove the call from the call manager without waiting for the acknowledgment
	s.callMgr.RemoveCall(reqData.CallId)

	return nil
}
